'''
Created on 21/11/2011

@author: Marina
'''
from bloque import Bloque
from infoProgram import ProgramAdress

class Continue:
    '''
    iniclilizo los bloques con le tamanio de la memoria, puse asi por poner un  valor hay que ver
    como crear un array con tamanio fijo.
    '''
    def __init__(self, method, memory):
        self.method = method
        self.logicalMemorySize = memory.getSize() 
        self.logicalMemory = [Bloque(0, self.logicalMemorySize-1, self.logicalMemorySize)]#saque el +1
        self.programTable ={}
        self.memory=memory
        self.kernel=None
           
    def load(self,mmu, program, pid):
        
        pSize = program.programSize
        print "hay suficiente espacio para cargarme? %s"%(self.isSufficientSpace(pSize))
        if self.isSufficientSpace(pSize):
            pos = self.method.getPhisicalAdress(self, program, mmu)
            self.completeLoad(self.memory, pos, program)
            self.programTable[pid] = ProgramAdress(pos, pSize)
            print "cargando..."
            print "pid:%d"%pid
            print "dirBase:%d"%self.programTable[pid].dirBase
            print "tamanio:%d"%self.programTable[pid].programSize
            print self.memory

    
    def completeLoad(self, memory, pos, program):
        d = pos
        source = program.sourceCode
        for inst in source:
            memory.load(d,inst)
            d=d+1
            
    def compactLoad(self,mmu, programTab):
        
        codigos = []
        codigoPrograma=[]
        
        for pid in self.programTable:
            prog = self.programTable[pid]
            pSize = prog.getSize()
        
            for pc in range(pSize):
                codigoPrograma.append(self.read(mmu,pid,pc))
            codigos.append(codigoPrograma)    
            #pos = self.method.getPhisicalAdress(self, prog, mmu)
        
        
        self.limpiarRam()
        print self.memory.memory
        print 1
        dirB = 0
        size = 0
        for codigoPrograma in codigos:
            
            self.compactCompleteLoad(self.memory, dirB, codigoPrograma)
            dirB = dirB + len(codigoPrograma)
            #self.returnPid(pos)
            self.programTable[pid] = ProgramAdress(dirB, pSize)
            size+= len(codigoPrograma)
        
        self.makeNewBloque(dirB, (self.memory.memorySize-size))
        
        '''
        print "cargando..."
        print "pid:%d"%pid
        print "dirBase:%d"%self.programTable[pid].dirBase
        print "tamanio:%d"%self.programTable[pid].programSize
        '''
    
    def compactCompleteLoad(self, memory, pos, programCode):
        d = pos
        for inst in programCode:
            memory.load(d,inst)
            d=d+1
        
        
    def limpiarRam(self):
        ds=self.memory.memory.keys()
        for d in ds:
            del self.memory.memory[d]
        self.logicalMemory = []
        print self.memory
            
    # def returnPid(self, pid):
    #return pid
    
    def read(self,mmu, pid, pc):
        print "[mmu]disposicion de los bloques:%s"%self.logicalMemory
        
        pSize=self.kernel.pcbt[pid].size
        print "volumen del programa que se quiere cargar: %d" % (pSize)
        
        if self.processInRAM(pid):
            print self.programTable[pid].dirBase
            print "si que esta en ram"
            dirFisica = ((self.programTable[pid]).dirBase)+pc
            return self.memory.read(dirFisica)
            
        elif self.isSufficientSpace(pSize) and not self.method.entraEnUnBloque(self, pSize): #este metodo hay que agregarlo a las tres estrategias
            self.compactation()
            return self.read(mmu, pid, pc)
        else:    
            pcb= self.kernel.pcbt[pid]
            program=mmu.disc.disk[pcb.name]
            self.algoritmoDeReemplazo(mmu,program, pid)
            return self.read(mmu, pid, pc)
            
        #dirFisica = ((self.programTable[pid]).dirBase)+pc
        #return self.memory.read(dirFisica)
        
    def unload(self,mmu, pid):
        
        
        prog = self.programTable[pid]
        d = prog.dirBase
        s = prog.programSize
        mem = self.memory
        self.completeUnload(mem,d,s)
        del self.programTable[pid]
        
        for bloque in self.logicalMemory:
            if bloque.getValorInferior()==d:
                
                return bloque.setValorInferior(s+d)
                #bloque.setVolumen(bloque.getVolumen()+s-1)
            else:
                if bloque.getValorSuperior()==(d+s):
                    
                    return bloque.setValorSuperior(bloque.getValorSuperior()-s)
                
                    #bloque.setVolumen(bloque.getVolumen()+s-1)
                else: 
                    return self.makeNewBloque(d, s)

    def makeNewBloque(self, direccionBase, size):

        bloqueNuevo = Bloque(direccionBase, (direccionBase+size)-1, size)
        self.logicalMemory.append(bloqueNuevo)
        print "hago nuevo bloque" 
        self.logicalMemory = sorted(self.logicalMemory, key = lambda bloque:bloque.getValorSuperior())
        print self.logicalMemory
        #self.compactBloques()
    
                    
    def completeUnload(self, memory, dirBase, size):
        while size > 0:
            memory.unload(dirBase)
            dirBase = dirBase+1
            size = size-1
            
    def isSufficientSpace(self, pSize):
        
        volumenTotal = 0
        
        print self.logicalMemory
        
        for bloque in self.logicalMemory:
            print "este es el volumen del bloque:"
            print bloque.getVolumen()
            volumenTotal = volumenTotal + bloque.getVolumen()
         
        print "este es el volumen total del bloque:"
        print volumenTotal    
        es = volumenTotal >= pSize
        print es
        return es 

    def swap(self, pcbToDisk):
        
        
        t = self.programTable.keys()
        
        
        if not t == []:    
            self.unload(pcbToDisk.pid)
        #manager.disc.load(programToDisc)
        #self.load(program)     
        
    def loadToDisk(self, pid, program, manager):
        manager.disc.load(pid, program)
        print "Se cargo un programa en disco..."
        print manager.disc
    
        
    def getPhisicalAdress(self, program, mmu):
        self.method.getPhisicalAdress(self, program, mmu)


    
    def compactation(self):
        print "COMPACTANDO NOM NOM NOM"
        #currentMethod = self.method
        #self.method = FirstAdjust()
        
        self.compactLoad(self.kernel.memoryManager, self.programTable)
        '''
        for pid in self.programTable:
            self.compactLoad(self.kernel.memoryManager ,self.programTable[pid], pid)
        '''
        #self.method = currentMethod 



    def hayEspacio(self, programSize):
        espacioTotal = 0
        for bloque in self.logicalMemory():
            espacioTotal = espacioTotal + bloque.getVolumen()
        
        print "el espacio total es &d" % (espacioTotal)
        return espacioTotal>=programSize


        
    def processInRAM(self, pid):
        
        
        
        for k  in self.programTable:
            if k == pid:
                return True
            
        return False
             
    def contextSwitch(self,mmu, program, pid , pcbToDisk):
    
    
        self.unload(mmu, pcbToDisk.pid)
        
        pSize = program.programSize
        
        print "SWITCH es sufiente espacio y entra en un bloque"
        
        if self.isSufficientSpace(pSize) and not self.method.entraEnUnBloque(self, pSize):
            self.compactation()
            self.load(mmu,program, pid)
        else:
            self.algoritmoDeReemplazo(mmu, program, pid)
            
    def algoritmoDeReemplazo(self,mmu,program, pid):
        claves=[]
        for k in self.programTable:
            claves.append(k)
        print "hay claves?%s"%(claves)
        if len(claves) is not 0 and not self.isSufficientSpace(program.programSize):
            pcbToDisk = self.kernel.pcbt[claves[0]]
            
            print "[mmu] expropiar a: %s" % (pcbToDisk)
            self.contextSwitch(mmu, program, pid , pcbToDisk)
        else:
            print "estoy entrando por aca, claramente"
            self.load(mmu, program, pid)
        
    def cargarPaginas(self,mmu, program, pid):
            '''
            '''
        